<?php

namespace App\Http\Controllers\Admin;

use Illuminate\Http\Request;

use App\Http\Controllers\Controller;

use App\Models\PriDeviceInfo;

use Cache;

use App\Models\Deviceparam;

use App\Models\Devicecontrol;
use App\Models\Devicecontrolparam;
use App\Models\Subdevicetype;
use App\Models\Userdesubdev;
use DB;

/**
 * 控制管理 
 */
class ControlController extends Controller
{
    use \App\Http\Traits\UserPrivilege;
    
    //三个线路控制的
    const SUB_TYPE = 1;
    
    //控制中心
    public function index() {
        
    }
    
    /**
     * @api {post} /control/:pdi/update 更新状态
     * @apiDescription 更新设备状态
     * @apiGroup 控制中心
     * @apiPermission none
     * @apiParam {Number} pdi 设备编号
     * @apiParam {String} field 控制设备状态的字段名
     * @apiParam {Number} dpt_id 设备分类
     * @apiParam {Number} value 设备状态
     * @apiSuccessExample {json} 成功:
     *     HTTP/1.1 201
     *     {
     *         "code": 0,
     *         "message": "",
     *              
     *     }
     * @apiErrorExample {json} 失败:
     *     HTTP/1.1 422
     *     {
     *       "code": -1,
     *       "message": "保存失败"
     *     }
     */
    public function update(Request $request, $pdi) {
        $user = $this->user();
        $cid = $user->Co_ID;
        $where = [
            ['pdi_index', '=', $pdi]
        ];
        $isExist = PriDeviceInfo::where($where)->count();
        if(!$isExist) {
            return $this->error('该公司不存在此设备');
        }

        $status = $request->input('value');
        $field = $request->input('field');
        $dptId = $request->input('dpt_id');
        
        $models = config('device.models');
        if(!array_key_exists($dptId, $models)){
             return $this->error('设备类型不存在');
        }
        $model = $models[$dptId];

        $statusInfo = $model::where('pdi_index','=',$pdi)->first();
        if(!$statusInfo) {
            return $this->error('设备状态数据不存在');
        }
        
        $statusInfo->$field = $status;
        
        if(!$statusInfo->save()) {
            $this->error('状态保存失败');
        }
    }
    
    /**
     * @api {get} /control/device 获取设备
     * @apiDescription 获取设备
     * @apiGroup 控制中心
     * @apiPermission none
     * @apiParam {Number} value 区域编号
     * @apiSuccess {Object[]} devices 设备信息
     * @apiSuccess {Object[]} types 设备分类
     * @apiSuccess {Object} icon 设备图标
     * @apiSuccessExample {json} 成功:
     *     HTTP/1.1 201
     *     {
     *         "code": 0,
     *         "data": {
     *              "devices": {},
     *              "types": {},
     *              "icon": {}
     *          },
     *              
     *     }
     * @apiErrorExample {json} 失败:
     *     HTTP/1.1 422
     *     {
     *       "code": -1,
     *       "message": "保存失败"
     *     }
     */
    public function device(Request $request) {
        $user = $this->user();
        $areaId = $request->input('value');
        $deviceTypeIds = config('device.control');
        $device = PriDeviceInfo::where('AreaId','=',$areaId)
                ->with(['types'=>function($query){
                    $query->select(['dt_typename', 'dt_typememo', 'dt_typeid']);
                }])
                ->whereIn('dpt_id', array_keys($deviceTypeIds))
                ->select(['AreaId', 'dpt_id', 'pdi_name', 'Co_ID', 'pdi_index'])
                ->get();
        $types = [];
        $result = [];
        foreach ($device->toArray() as  $v) {
            $result[$v['AreaId']][$v['dpt_id']][] = $v;
            $types[$v['AreaId']][$v['dpt_id']] = $v['types'];
        }
        return ["data"=>[ 'devices' => $result, 'types' => $types, 'icon'=>$deviceTypeIds ]];
    }
    
    /**
     * @api {get} /control/devicedata 获取设备参数
     * @apiDescription 获取设备参数
     * @apiGroup 控制中心
     * @apiPermission none
     * @apiParam {Number} pdi_index 设备编号
     * @apiSuccess {Number} pdi_index 设备编号
     * @apiSuccess {Number} rd_NetCom 设备网络通讯状态
     * @apiSuccess {Datetime} rd_updatetime 设备数据更新时间
     * @apiSuccess {Object[]} in  设备输入
     * @apiSuccess {Object[]} out 设备输出
     * @apiSuccess {Object[]} sub 设备子分类
     * @apiSuccessExample {json} 成功:
     *     HTTP/1.1 201
     *     {
     *         "code": 0,
     *         "devicesData": {
     *              "pdi_index": "",
     *              "rd_NetCom": "",
     *              "rd_updatetime": "",
     *              "in": {},
     *              "out": {},
     *              "sub": {}
     *          },
     *              
     *     }
     * @apiErrorExample {json} 失败:
     *     HTTP/1.1 422
     *     {
     *       "code": -1,
     *       "message": "保存失败"
     *     }
     */
    public function deviceData(Request $request) {
        // $dptId = $request->input('dpt_id');
        $pdiIndex = $request->input('pdi_index');
        $pdiInfo = PriDeviceInfo::find($pdiIndex);
        $dptId = null;
        if($pdiInfo) {
            $dptId = $pdiInfo->dpt_id;
        }
        $models = config('device.map_models');
        if(!array_key_exists($dptId, $models)){
             return $this->error('设备不存在');
        }
        $model = $models[$dptId]['real'];
        $data = $model::where('pdi_index', '=', $pdiIndex)
                ->first();
        $cacheKey = 'control:params:'.$pdiIndex;
        $params = Cache::get($cacheKey);
        if(!$params) {
            $prefix = 'rd_';
            $params = Deviceparam::where('dt_typeid', '=', $dptId)
                    ->select(['Dp_id', 'dp_paramname', 'dp_paramdesc', 'dp_cmdup'])
                    ->get()
                    ->map(function($item) use($prefix){
                        $item->rid = $this->getCommandId($item->Dp_id, $item->dp_cmdup);
                        $item->dp_paramname = $prefix.$item->dp_paramname;
                        return $item;
                    })
                    ->keyBy('dp_paramname')->toArray();
            Cache::put($cacheKey, $params);
        }
       // dd($params);
        $fields = ['in'=>'rd_SWDI', 'ou'=>'rd_SWDO'];
        $nums = range(1,16);
        $result = [];
        $out = null;
        
        if($data) {
            $configData = $this->getConfigData($pdiIndex, $dptId);
            foreach ($fields as  $fKey => $field) {
                foreach ($nums as $index) {
                    $fieldKey = $field.$index;
                    
                    $result[$fKey][$index] = array_merge(
                            $params[$fieldKey], 
                            [ 'status' => (int)$data[$fieldKey], 'bStatus'=> $this->getStatus($data[$fieldKey], $fKey), 'index' => $index  ],
                            isset($configData[$params[$fieldKey]['Dp_id']])?$configData[$params[$fieldKey]['Dp_id']]:[]
                        );
                } 
            }
            $sub = Subdevicetype::where('ts_Maintypeid', '=', $dptId)->get();
            $out = [
                'pdi_index' => $data['pdi_index'],
                'rd_NetCom' => $data['rd_NetCom'],
                'rd_updatetime' => $data['rd_updatetime'],
                'in' => $result['in'],
                'out' => $this->formatOut($result['ou']),
                'sub' => $sub,
            ]; 
        }

        return $this->success(null, [ 'devicesData' => $out,  ]);
    }
    
    //计算deviceparam dp_id
    private function getCommandId($dpId, $dcmup=6) {
        return $dpId - 65536 * $dcmup;
    }
    
    //获取dp_id对应关系
    private function getCid($pdiIndex) {
        $cacheKey = 'control:params:'.$pdiIndex;
        $params = Cache::get($cacheKey);
        return $params;
    }
    
    //设置状态
    private function getStatus($status, $type) {
        if($type=='in') {
            return $status==0?true:false;
        }else{
            return $status==1?true:false;
        }
    }
    
    //获取配置数据
    protected function getConfigData($pdiIndex, $dptId) {
        return Userdesubdev::where('tu_pdi_index', '=', $pdiIndex)
                ->where('tu_TypeId', '=', $dptId)
                ->select(['tu_SubTypeId', 'tu_SubCha', 'tu_WarnMo as dp_paramdesc', 'tu_Warnid', 'tu_index', 'ts_TypeMo', 'ts_Icon'])
                ->leftJoin('t_Subdevicetype', function($join)use($dptId){
                    $join->on('t_Subdevicetype.ts_typeid', '=', 't_UserDeSubDev.tu_SubTypeId')
                         ->where('t_Subdevicetype.ts_Maintypeid', '=', $dptId);
                })
                ->get()
                ->keyBy('tu_Warnid')->toArray();
    }
    
    /**
     * @api {post} /control/command 保存命令
     * @apiDescription 保存命令
     * @apiGroup 控制中心
     * @apiPermission none
     * @apiParam {Number} pdi_index 设备编号
     * @apiParam {Object[]} params 设备控制参数
     * @apiParam {Object} param 设备控制参数
     * @apiParam {Number} param.dp_id 设备控制编码
     * @apiParam {Number} param.status 设备控制状态
     * @apiSuccessExample {json} 成功:
     *     HTTP/1.1 201
     *     {
     *         "code": 0,
     *         "message": ""
     *              
     *     }
     * @apiErrorExample {json} 失败:
     *     HTTP/1.1 422
     *     {
     *       "code": -1,
     *       "message": "保存失败"
     *     }
     */
    public function saveCommand(Request $request) {
        $pdi = $request->input('pdi_index'); 

        try {
            $info = PriDeviceInfo::findOrFail($pdi);
        } catch (\Throwable $th) {
            return $this->error('该公司不存在此设备');
        }

       $ret = false;
       DB::transaction(function () use($request, $pdi, &$ret){
            $post = $request->input('params');
            foreach ($post as $record) {
                $time = date('Y-m-d H:i:s');
                $data = [
                        'pdi_index' => $pdi,
                        'dc_datetime0'=>$time,
                        'Dc_status'=>1,
                        'dc_username'=>$request->user()->username,
                        'dc_userid'=>$request->user()->userid
                ];
                
                $ret1 = Devicecontrol::create($data); 
                $params = [
                    'Dp_id'=> $this->getCommandId($record['dp_id']),
                    'dcp_value'=>$record['status'],
                    'dc_index'=>$ret1->dc_index
                ];

                $ret2 = Devicecontrolparam::create($params);
            }

            $ret = ($ret1 && $ret2);
       });

        
        if(!$ret) {
            $this->error('设置失败');
        }
    }
    
    /**
     * @api {post} /control/switch 保存开关量
     * @apiDescription 保存开关量
     * @apiGroup 控制中心
     * @apiPermission none
     * @apiParam {Number} pdi_index 设备编号
     * @apiParam {Number} subtype 设备子分类
     * @apiParam {Number} dp_id 设备控制编码
     * @apiParam {Number} sindex 开关量编号
     * @apiParam {String} [desc] 开关量描述
     * @apiSuccessExample {json} 成功:
     *     HTTP/1.1 201
     *     {
     *         "code": 0,
     *         "message": ""
     *              
     *     }
     * @apiErrorExample {json} 失败:
     *     HTTP/1.1 422
     *     {
     *       "code": -1,
     *       "message": "保存失败"
     *     }
     */
    public function saveInputData(Request $request) {
        $pdi = $request->input('pdi_index'); 
        $where = [
            ['pdi_index', '=', $pdi]
        ];
        $info = PriDeviceInfo::where($where)->first();
        if(!$info) {
            return $this->error('该公司不存在此设备');
        }
        $dpId = $request->input('dp_id');
        $switchIndex = $request->input('sindex');
        $mainType = $info->dpt_id;
        $desc = $request->input('desc');
        $subType = $request->input('subtype');

        $data = [
            'tu_pdi_index' => $pdi,
            'tu_Warnid'=> $dpId,
            'tu_TypeId'=> $mainType,
            'tu_SubTypeId'=> $subType,
            'tu_SubCha'=> $switchIndex,
        ];
        $fwhere = [
            [ 'tu_pdi_index', '=', $pdi ],
            [ 'tu_Warnid', '=', $dpId ],
            [ 'tu_TypeId', '=', $mainType ],
            [ 'tu_SubCha', '=', $switchIndex ],
        ];
        $find = Userdesubdev::where($fwhere)->first();
        if($find) {
            $ret = $find->update([
                'tu_SubTypeId' => $subType,
                'tu_WarnMo' => $desc,
            ]);
        }else{
            $data['tu_WarnMo'] = $desc;
            $ret = Userdesubdev::create($data);
        }
        if(!$ret) {
            $this->error('保存失败');
        }
    }
    
    /**
     * @api {post} /control/out 继电器输出
     * @apiDescription 保存继电器输出
     * @apiGroup 控制中心
     * @apiPermission none
     * @apiParam {Number} pdi_index 设备编号
     * @apiParam {Number} subtype 设备子分类
     * @apiParam {Number} dp_id 设备控制编码
     * @apiSuccessExample {json} 成功:
     *     HTTP/1.1 201
     *     {
     *         "code": 0,
     *         "message": ""
     *              
     *     }
     * @apiErrorExample {json} 失败:
     *     HTTP/1.1 422
     *     {
     *       "code": -1,
     *       "message": "保存失败"
     *     }
     */
    public function saveOutputData(Request $request) {
        $pdi = $request->input('pdi_index'); 
        $where = [
            ['pdi_index', '=', $pdi]
        ];
        $info = PriDeviceInfo::where($where)->first();
        if(!$info) {
            return $this->error('该公司不存在此设备');
        }
        $dpId = $request->input('dp_id');
        $mainType = $info->dpt_id;
        $subType = $request->input('subtype');
        
        $ids = $this->getControlId($pdi, $subType);
        
        if(!$ids && !$dpId) {
            return $this->error('没有可分配资源,请选择其他类型');
        }
        
        $fwhere = [
            [ 'tu_pdi_index', '=', $pdi ],
            [ 'tu_TypeId', '=', $mainType ],
        ];
        $find = Userdesubdev::where($fwhere)
                    ->whereIn( 'tu_Warnid', $dpId )
                    ->get();
        if(!$find->isEmpty()) {
            $first = $find->first();
            if(($first->tu_SubTypeId == self::SUB_TYPE && $subType != self::SUB_TYPE) 
                    || ($first->tu_SubTypeId != self::SUB_TYPE  && $subType == self::SUB_TYPE)) {
                if(!$ids) {
                    return $this->error('没有可分配资源,请选择其他类型');
                }
                $ret = Userdesubdev::where($fwhere)
                    ->whereIn( 'tu_Warnid', $dpId )
                    ->delete();
                $this->addConfig($pdi, $subType, $mainType, $ids);
            }else{
                    $ret = Userdesubdev::where($fwhere)
                    ->whereIn( 'tu_Warnid', $dpId )
                    ->update([
                        'tu_SubTypeId' => $subType,
                    ]);  
            }

        }else{
           $ret =  $this->addConfig($pdi, $subType, $mainType, $ids);
        }
        if(!$ret) {
            $this->error('保存失败');
        }
    }
    
    //添加配置
    private function addConfig($pdi, $subType,$mainType, $ids) {
        $insert = [];
        foreach ($ids as $index => $id) {
            $insert[] = [
                'tu_pdi_index' => $pdi,
                'tu_Warnid'=> $id,
                'tu_TypeId'=> $mainType,
                'tu_SubTypeId'=> $subType,
                'tu_SubCha'=> $index,
            ];
        }
        return DB::table('t_UserDeSubDev')->insert($insert);
    }
    
    private $threeIds = [
        1=>434601,
        2=>434602,  
    ];
    private $twoIds = [ 
        3=>434603, 
        4=>434604, 
        5=>434605, 
        6=>434606, 
        7=>434607,
    ];

    //获取控制id
    protected function getControlId($pdiIndex, $subtype) {
        if($subtype==1) {
            $ids = $this->threeIds;
            $len = 2;
        }else{
            $ids = $this->twoIds;
            $len = 1;
        }

        $find = Userdesubdev::where( 'tu_pdi_index', '=', $pdiIndex)
                ->whereIn('tu_Warnid', $ids)
                ->select(['tu_Warnid', 'tu_SubCha'])
                ->get()
                ->pluck('tu_Warnid', 'tu_SubCha');
        $result = [];
        if($find->count()) {
            $result = collect($ids)->diffKeys($find)->slice(0, $len)->toArray();
            
        }else{
            $result = collect($ids)->slice(0, $len);
        }
        return $result;
    }
    
    //格式化输出
    protected function formatOut($data) {
        return  $this->formatGroup(collect($data));
    }
    
    // 分组
    protected function formatGroup($result) {
        $out = [];
        $allocate = [];
        $three = $result->whereIn('tu_Warnid', array_values($this->threeIds), false)->toArray();
        $i = 0;
        $len = 2;
        $total = 6;
        while($arr = array_slice($three,$i,$len)) {
            $lastIndex = (int)array_get(end($arr), 'tu_index');
            if($lastIndex) {
                $allocate[$lastIndex] = $arr;
            }
            
            $i+=$len;
        }
        $len = 1;
        $two = $result->whereIn('tu_Warnid', array_values($this->twoIds), false)->toArray();
        $i = 0;
        while($arr = array_slice($two,$i,$len)) {
            $lastIndex = (int)array_get(end($arr), 'tu_index');
            if($lastIndex) {
                $allocate[$lastIndex] = $arr;
            }
            $i+=$len;
        }
        ksort($allocate, SORT_NUMERIC);
        return array_pad(array_values($allocate), $total, []);
    }
}
